package com.alibaba.dubbo.registry;


import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

import com.alibaba.dubbo.common.logger.Logger;
import com.alibaba.dubbo.common.logger.LoggerFactory;
import com.lvmama.config.common.ZooKeeperConfigProperties;

/**
 * 为了提高启动速度，会把consumer对服务的注册和订阅改成异步的。
 * 在第一次调用某个服务的时候，需要确保已经进行过订阅，否则可能会调用到失效的provider。
 * 本类用来记录已经完成订阅、注册的服务列表。
 * <p>
 * ZookeeperRegistry类完成订阅、注册后会记录到这里来。
 * <p>
 * AbstractClusterInvoker.invoke()调用服务之前会先检查是否已经完成了订阅、注册。
 *
 * @author Administrator
 */
public class RegistryHistory {
	private static final Logger logger = LoggerFactory.getLogger(RegistryHistory.class);

	private static final String EMPTY_VALUE = "";
	private static final ConcurrentHashMap<String, String> REGISTERD_SERVICES = new ConcurrentHashMap<String, String>();
	private static final ConcurrentHashMap<String, String> REGISTER_IMMEDIATE_SERVICES = new ConcurrentHashMap<String, String>();
	private static final ConcurrentHashMap<String, String> REGISTING_SERVICES = new ConcurrentHashMap<String, String>();
	private static final ConcurrentHashMap<String, String> SUBSCRIBED_SERVICES = new ConcurrentHashMap<String, String>();
	private static final ConcurrentHashMap<String, String> SUBSCRIBE_IMMEDIATE_SERVICES = new ConcurrentHashMap<String, String>();
	private static final ConcurrentHashMap<String, String> SUBSCRIBING_SERVICES = new ConcurrentHashMap<String, String>();

	public static void doRegister(String serviceName) {
		REGISTER_IMMEDIATE_SERVICES.remove(serviceName);
		REGISTERD_SERVICES.put(serviceName, EMPTY_VALUE);
	}

	public static void doSubscribe(String serviceName) {
		SUBSCRIBE_IMMEDIATE_SERVICES.remove(serviceName);
		SUBSCRIBED_SERVICES.put(serviceName, EMPTY_VALUE);
	}

	public static boolean isRegistered(String serviceName) {
		return REGISTERD_SERVICES.containsKey(serviceName);
	}

	public static boolean isSubscribed(String serviceName) {
		return SUBSCRIBED_SERVICES.containsKey(serviceName);
	}

	public static boolean needImmediateRegister(String serviceName) {
		return REGISTER_IMMEDIATE_SERVICES.containsKey(serviceName);
	}

	public static void markAsImmediateRegister(String serviceName) {
		REGISTER_IMMEDIATE_SERVICES.put(serviceName, EMPTY_VALUE);
	}

	public static String removeFromImmediateRegister(String serviceName) {
		return REGISTER_IMMEDIATE_SERVICES.remove(serviceName);
	}

	public static boolean needImmediateSubscribe(String serviceName) {
		return SUBSCRIBE_IMMEDIATE_SERVICES.containsKey(serviceName);
	}

	public static void markAsImmediateSubscribe(String serviceName) {
		SUBSCRIBE_IMMEDIATE_SERVICES.put(serviceName, EMPTY_VALUE);
	}

	public static String removeFromImmediateSubscribe(String serviceName) {
		return SUBSCRIBE_IMMEDIATE_SERVICES.remove(serviceName);
	}

	public static boolean putToSubscribing(String serviceName) {
		if (SUBSCRIBING_SERVICES.putIfAbsent(serviceName, EMPTY_VALUE) != null) {
			//这个service正在处理中
			return false;
		} else {
			return true;
		}
	}

	public static void removeFromSubscribing(String serviceName) {
		SUBSCRIBING_SERVICES.remove(serviceName);
	}
//	public static boolean isSubscribing(String serviceName){
//		return SUBSCRIBING_SERVICES.containsKey(serviceName);
//	}

	public static boolean putToRegisting(String serviceName) {
		if (REGISTING_SERVICES.putIfAbsent(serviceName, EMPTY_VALUE) != null) {
			//这个service正在处理中
			return false;
		} else {
			return true;
		}
	}

	public static void removeFromRegisting(String serviceName) {
		REGISTING_SERVICES.remove(serviceName);
	}
//	public static boolean isRegisting(String serviceName){
//		return REGISTING_SERVICES.containsKey(serviceName);
//	}


	private static boolean isAsyncSubscribe = false;
	private static boolean isAsyncRegister = false;
	private static Long concurrentSubscribeTimeoutMS = 2000L;

	static {
		try {
			Properties prop = new Properties();
			prop.load(RegistryHistory.class.getResourceAsStream("/dubbo.properties"));

			String isAsyncSubscribeProp = prop.getProperty("isAsyncSubscribe");
			String isAsyncRegisterProp = prop.getProperty("isAsyncRegister");
			String concurrentSubscribeTimeoutMSProp = prop.getProperty("concurrentSubscribeTimeoutMS");

			initAsyncInfo(isAsyncSubscribeProp, isAsyncRegisterProp, concurrentSubscribeTimeoutMSProp);
		} catch (Exception e) {
			logger.error("Init RegistryHistory warn : " + e.getMessage());
			try {
				String isAsyncSubscribeProp = ZooKeeperConfigProperties.getProperties("isAsyncSubscribe");
				String isAsyncRegisterProp = ZooKeeperConfigProperties.getProperties("isAsyncRegister");
				String concurrentSubscribeTimeoutMSProp = ZooKeeperConfigProperties.getProperties("concurrentSubscribeTimeoutMS");

				initAsyncInfo(isAsyncSubscribeProp, isAsyncRegisterProp, concurrentSubscribeTimeoutMSProp);
			} catch (Exception ee) {
				logger.error("Init RegistryHistory error.", ee);
			}
		}
	}

	private static void initAsyncInfo(String isAsyncSubscribeProp, String isAsyncRegisterProp, String concurrentSubscribeTimeoutMSProp) {
		logger.info("isAsyncSubscribeProp:" + isAsyncSubscribeProp);
		logger.info("isAsyncRegisterProp:" + isAsyncRegisterProp);
		logger.info("concurrentSubscribeTimeoutMSProp:" + concurrentSubscribeTimeoutMSProp);

		if ("Y".equalsIgnoreCase(isAsyncSubscribeProp) || "true".equalsIgnoreCase(isAsyncSubscribeProp)) {
			isAsyncSubscribe = true;
		}

		if ("Y".equalsIgnoreCase(isAsyncRegisterProp) || "true".equalsIgnoreCase(isAsyncRegisterProp)) {
			isAsyncRegister = true;
		}

		if (concurrentSubscribeTimeoutMSProp != null && concurrentSubscribeTimeoutMSProp.length() > 0) {
			try {
				concurrentSubscribeTimeoutMS = Long.valueOf(concurrentSubscribeTimeoutMSProp);
			} catch (Exception e) {
				logger.error("convert concurrentSubscribeTimeoutMSProp to Long error. ", e);
			}
		}
	}

	public static boolean isAsyncSubscribe() {
		return isAsyncSubscribe;
	}

	public static boolean isAsyncRegister() {
		return isAsyncRegister;
	}

	public static Long getConcurrentSubscribeTimeoutMS() {
		return concurrentSubscribeTimeoutMS;
	}
}
